﻿using Nop.Core;
using Nop.Core.Domain.Logistics;
using Nop.Services.Common;
using System.Collections.Generic;
using System;

namespace Nop.Services.Logistics
{
    public static class AddtionalChargeHelper
    {
        public static Dictionary<AddtionalAttributes, IAddtionalChargeHandler> Handlers = null;

        public static decimal GetAddtionalCharge(PackageInformation packageInfo)
        {
            decimal total = 0M;
            foreach (AddtionalAttributes att in Handlers.Keys)
            {
                if (packageInfo.AddtionalAttributes.HasFlag(att))
                {
                    total += Handlers[att].GetCharge(packageInfo);
                }
            }
            return total;
        }
    }

    public interface IAddtionalChargeHandler
    {
        decimal GetCharge(PackageInformation packageInfo);
    }

    public class FlatCharge : IAddtionalChargeHandler
    {
        private decimal charge;

        public FlatCharge(decimal charge)
        {
            this.charge = charge;
        }

        public virtual decimal GetCharge(PackageInformation packageInfo)
        {
            return charge;
        }
    }

    public class PercentCharge : IAddtionalChargeHandler
    {
        private decimal percentage;
        private decimal maxValue;

        public PercentCharge(decimal percentage, decimal maxValue)
        {
            this.percentage = percentage;
            this.maxValue = maxValue;
        }

        public virtual decimal GetCharge(PackageInformation packageInfo)
        {
            return 0M;
        }
    }

    public class InsuranceCharge : IAddtionalChargeHandler
    {
        private decimal step;
        private decimal chargePerStep;
        private decimal maxValue;

        public InsuranceCharge(decimal chargePerStep, decimal maxValue, decimal step)
        {
            this.chargePerStep = chargePerStep;
            this.maxValue = maxValue;
            this.step = step;
        }

        public virtual decimal GetCharge(PackageInformation packageInfo)
        {
            if (packageInfo.InsuranceValue.HasValue)
            {
                if (packageInfo.InsuranceValue.Value > maxValue)
                {
                    throw new NopException("Insurance value larger than {0}", maxValue);
                }

                if (packageInfo.InsuranceValue.Value <= step)
                {
                    return 0M;
                }

                return MathEx.Round(Math.Ceiling((packageInfo.InsuranceValue.Value - step) / step) * (chargePerStep));
            }

            return 0M;
        }
    }
}
